跳到主要内容

异步

异步编程是处理耗时操作(如网络请求、文件读写、定时器)的核心机制。在 ES6+ 提出了 Promiseasyncawait 用于解决回调地狱(Callback hell)问题,使代码更易读和维护。

Promise: 异步操作的标准化封装

Promise 是 ES6 引入的异步操作容器,用于表示一个异步操作最终完成(或失败)以及结果值。

三种状态

  • pending(等待中):初始状态
  • fulfilled(已成功):操作成功完成
  • rejected(已失败):操作失败

状态不可逆,一旦从 pending 变成 fulfilledrejected ,无法再更改

错误

Promise 的错误必须显示捕获

  • Promise 链中的错误(reject 或抛出异常)不会终止程序,需通过 .catchtry/catch(配合 async/await) 捕获。
Promise.reject('错误').catch(err => {
console.log(err);
});

避免冗余使用

若异步操作本身返回 Promise,无需使用 new Promise 封装,直接返回即可。

// 冗余封装
function fetchData() {
return new Promise((resolve, reject) => {
// 直接返回 fetch 的 Promise
fetch(url).then(resolve).catch(reject);
});
}

Promise.all

Promise.all 等待所有的 Promise 成功,或任意一个失败(立即拒绝)。

当执行的数组为空,立即返回 Promise 成功。

Promise.all([fetch(url1), fetch(url2)])
.then(responses => Promise.all(responses.map(res => res.json())))
.catch(err => console.log('至少一个请求失败'));

Promise.race

Promise.race 返回第一个完成的 Promise (无论成功或是失败)。

const timeout = new Promise((_, reject) =>
setTimeout(() => reject('请求超时'), 5000),
);
Promise.race([fetch(url), timeout])
.then(res => console.log(res))
// 5秒未响应则报超时
.catch(err => console.log(err));

Promise.allSettled

ES2020 引入了 Promise.allSettled ,返回一个包含所有的 Promise 结果的对象数组,即便是不分异步操作结果是失败。

Promise.allSettled([fetch(url1), fetch(url2)]).then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});

async/await:异步代码的同步写法

async/await 是 ES2017 引入的语法糖,基于 Promise 用于简化异步代码的书写。

async

声明一个返回 Promise 的函数

async function foo() {
// 等价于 return Promise.resolve(42)
return 42;
}

await

仅可在 async 中使用,暂停函数的执行,等待右侧 Promise 解决。

async function fetchData() {
// 等待 fetch 的 Promise 完成
const res = await fetch(url);
// 等待 res.json() 的 Promise 完成
const data = await res.json();
return data;
}

注意:await 仅暂停当前 async 函数的执行,不影响其他的异步操作

async function foo() {
console.log('start');
await Promise.resolve(); // 暂停 foo,但不阻塞全局
console.log('end');
}

foo();
console.log('全局'); // 输出顺序:start → 全局 → end

循环中的 await

在循环中使用 await 会导致每一个迭代等待前一个完成:

async function processArray(array) {
for (const item of array) {
// 顺序处理(耗时累加)
await processItem(item);
}
}

执行顺序

Promise.then微任务setTimeout宏任务

console.log('start');
setTimeout(() => console.log('timeout'), 0);

Promise.resolve().then(() => console.log('promise'));

console.log('end');

// 输出顺序:start → end → promise → timeout

注意

  • 未处理的 Promise 拒绝可能导致内存泄漏
  • 避免不必要的 await:若多个异步独立,用 Promise.all 并行处理
  • 避免在循环中无意义的 await:合并异步操作